package org.axed.user.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import java.util.ArrayList;
import org.axed.user.client.util.Tower;

/**
 * A String with a list of entry points.
 * This can be used as the start and stop positions of 
 * HTML representation of the characters.
 *
 * str : "H<i>e</i><b>ll</b>o&nbsp; World"
 * 
 * entries are indexed in str by the tower.
 *
 * <pre>
 * entry#       Entries        tower
 * ==========   ========   ===========
 *     0         [H]               0
 *     1         [<i>]       + 1 = 1
 *     2         [e]         + 3 = 4
 *     3         [</i>]      + 1 = 5
 *     4         [<b>]       + 4 = 9
 *     5         [l]         + 3 = 12
 *     6         [l]         + 1 = 13
 *     7         [</b>]      + 1 = 14
 *     8         [o]         + 4 = 18
 *     9         [&nbsp;]    + 1 = 19
 *    10         [ ]         + 6 = 25
 *    11         [W]         + 1 = 26
 *    12         [o]         + 1 = 27
 *    13         [r]         + 1 = 28
 *    14         [l]         + 1 = 29
 *    15         [d]         + 1 = 30
 * </pre>
 */

public class IndexString {
	/**
	 * The actual string.
	 */
	private StringBuffer str;

	/**
	 * Effectively receives the sums of all entries at specefic levels. 
	 */
	private Tower tower;

	/**
	 * Constructor;
	 */
	public IndexString() {
		tower = new Tower();
		str = new StringBuffer();
	}

	/**
	 * Constructor.
	 */
	public IndexString(String s) {
		tower = null;
		str = new StringBuffer(s);
	}

	/**
	 * Appends an entry
	 */
	public void appendEntry(String s) {
		if (tower == null) {
			buildTower();
		}

		tower.add(s.length());
		str.append(s);
	}

	/**
	 * Appends an entry.
	 */
	public void appendEntry(char c) {
		if (tower == null) {
			buildTower();
		}

		tower.add(1);
		str.append(c);
	}


	/**
	 * Clears the IndexString.
	 */
	public void clear() {
		if (tower != null) {
			tower.clear();
		}
		str.delete(0, str.length());
	}

	/**
	 * Returns a debug string.
	 */
	public String debug() {
		String s = new String();
		if (tower == null) {
			return "tower=null S:\"" + str + "\"";
		}

		s += "S:\"";
		for(int i = 0; i < tower.size(); i++) {
			if (i + 1 == tower.size()) {
				s += str.substring(tower.get(i), str.length());
				
			} else { 
				s += str.substring(tower.get(i), tower.get(i+1)) + ":";
			}
		}
	
		s += tower.debug();
		return s;
	}

	/**
	 * Returns the string where entry is embraced with
	 * s1 and s2.
	 *
	 * This function does not alter the IndexString.
	 */
	public String embraceEntry(int e, String s1, String s2) {
		if (tower == null) {
			buildTower();
		}

		StringBuffer s = new StringBuffer(str.toString());
		s.replace(getOffset(e), getEndOffset(e), s1 + retrieveEntry(e) + s2);
		return s.toString();
	}

	/**
	 * Inserts an entry at p.
	 */
	public void insertEntry(String s, int p) {
		if (tower == null) {
			buildTower();
		}

		str.insert(getOffset(p), s);
		tower.insert(s.length(), p);
	}

	/**
	 * Removes an entry.
	 */
	public void removeEntry(int p) {
		if (tower == null) {
			buildTower();
		}
		
		str.delete(getOffset(p), getEndOffset(p));
		tower.remove(p);
  	}

  	/**
	 * Deletes entries vom start until end. 
	 */
	public void removeEntries(int start, int end) {
		for (int i = start; i < end; i++) {
			removeEntry(start);
		}
	}
	
	/**
	 * Replaces an entry.
	 */
	public void replaceEntry(String s, int p) {
		if (tower == null) {
			buildTower();
		}

		str.replace(getOffset(p), getEndOffset(p), s);
		tower.set(p, s.length());
	}

	/**
 	 * Retrieves the entries from begin column until end column.
 	 */
	public String retrieveEntries(int begin, int end) {
		if (tower == null) {
			buildTower();
		}
		return str.substring(getOffset(begin), getOffset(end));
	}

	/**
 	 * Retrieves the entry at p.
 	 */
	public String retrieveEntry(int p) {
		return retrieveEntries(p, p + 1);
	}

	/**
	 * Returns the number of entries.
	 */
	public int entries() {
		if (tower == null) {
			buildTower();
		}
		return tower.size() - 1;
	}

	/**
	 * Returns the complete indexed string.
	 */
	public String toString() {
		return str.toString();
	}

//protects

	protected void towerAdd(char firstC, int p) {
		tower.add(p);
	}

	/**
	 * Build the towers. 
	 * It can have been null so far. For example if a huge block was pasted.
	 */
	protected void buildTower() {
		tower = new Tower();
		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);
			if (c == '&') {
				int p = 1;
				char fc = c;
				while (c != ';') {
					p++;
					i++;
					c = str.charAt(i);
				}
				towerAdd(fc, p);
			} else if (c == '<') {
				int p = 1;
				char fc = c;
				while (c != '>') {
					p++;
					i++;
					c = str.charAt(i);
				}
				towerAdd(fc, p);
			} else {
				towerAdd(c, 1);
			}
		}
	}

	/**
	 * Gets the offset of entry p.
	 */
	private int getOffset(int p) {
		return tower.get(p);
	}

	/**
	 * Gets the offset of the end of entry p.
	 */
	private int getEndOffset(int p) {
		return tower.get(p + 1);
	}
}
